﻿using System.Text;
using KongMing.Project.Entity.Common;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace KongMing.Project.Common.Sdk
{
    public class RabbitMQClient
    {
        /// <summary>
        /// 连接工厂
        /// </summary>
        public static ConnectionFactory factory;

        public RabbitMQClient(RabbitMQConfig config)
        {
            factory = new ConnectionFactory()
            {
                HostName = config.HostName,
                Port = config.Port,
                UserName = config.UserName,
                Password = config.Password,
                RequestedConnectionTimeout = TimeSpan.FromSeconds(10),//超时时间
                AutomaticRecoveryEnabled = true, //恢复连接机制 true 开启
            };
        }

        
        public static Lazy<NormalRabbitClient> NormalClient = new Lazy<NormalRabbitClient>();

        /// <summary>
        /// 创建连接
        /// </summary>
        public static IConnection CreateConnect()
        {
            var conn = factory.CreateConnection();
            return conn;
        }

        /// <summary>
        /// 绑定消费事件
        /// </summary>
        public static void BindConsumer(IModel rabbitChannel, string queueName, int count, bool returnToQueue, Func<string, BasicDeliverEventArgs, bool> action)
        {
            EventingBasicConsumer eventingBasic = new EventingBasicConsumer(rabbitChannel);
            eventingBasic.Received += (sender, e) =>
            {
                try
                {
                    var textBody = Encoding.UTF8.GetString(e.Body.ToArray());
                    if (action.Invoke(textBody, e))
                    {
                        rabbitChannel.BasicAck(e.DeliveryTag, false);
                    }
                    else
                    {
                        rabbitChannel.BasicNack(e.DeliveryTag, false, returnToQueue);
                    }
                }
                catch (Exception ex)
                {
                    rabbitChannel.BasicNack(e.DeliveryTag, false, returnToQueue);
                }
            };
            rabbitChannel.BasicQos(0, (ushort)count, false);
            rabbitChannel.BasicConsume(queueName, false, eventingBasic);
        }

        public static void BindConsumer(IModel rabbitChannel, string queueName, int count, bool returnToQueue, Func<string, bool> action)
        {
            BindConsumer(rabbitChannel, queueName, count, returnToQueue, (content, eventarg) => action.Invoke(content));
        }

        /// <summary>
        /// 通用RabbitMQ服务类
        /// </summary>
        public class NormalRabbitClient
        {
            IConnection connection;
            public IModel channel { get; private set; }
            object locker = new object();
            public void Connect()
            {
                if (connection != null)
                    return;
                lock (locker)
                {
                    if (connection != null)
                        return;
                    connection = CreateConnect();
                    channel = connection.CreateModel();
                }
            }

            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="exchange">交换机名</param>
            /// <param name="routingkey">路由键</param>
            /// <param name="msg">消息内容</param>
            public bool Push(string exchange, string routingkey, string msg)
            {
                try
                {
                    Connect();
                    var prop = channel.CreateBasicProperties();
                    prop.DeliveryMode = 2;
                    var body = new ReadOnlyMemory<byte>(Encoding.UTF8.GetBytes(msg));
                    channel.BasicPublish(exchange, routingkey, prop, body);
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }
            public void Close()
            {
                channel.Close();
                channel = null;
                connection.Close();
                connection = null;
            }
        }
    }
}
